
#include "config.h"
#include "lfs/flash.h"
#include "log/log2.h"

#define CFG_PAGE_MANU		1		//厂商配置页
#define CFG_PAGE_USER		2		//用户配置页

#define CFG_MANU_ADDR		(FLASH_BASE_ADDR + FLASH_SIZE - FLASH_PAGE_SIZE*CFG_PAGE_MANU)
#define CFG_USER_ADDR		(FLASH_BASE_ADDR + FLASH_SIZE - FLASH_PAGE_SIZE*CFG_PAGE_USER)

#define MAGIC_NUM(b0,b1,b2,b3)		(((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | ((uint32_t)(b2) << 8) | (uint32_t)(b3))
#define CFG_MAGIC			MAGIC_NUM('C','O','N','F')
//	#define MAGIC_MANU			MAGIC_NUM('M','A','N','U')
//	#define MAGIC_USER			MAGIC_NUM('U','S','E','R')

#define CFG_WAVELYNX(_addr)	(*((const volatile cfg_wavelynx_t*)_addr))

static const uint32_t cfg_page_addr[CFG_ID_MAX] = {CFG_MANU_ADDR, CFG_USER_ADDR};
//	static const uint32_t cfg_magics[CFG_ID_MAX] = {MAGIC_MANU, MAGIC_USER};
static uint8_t cfg_flag_init = 0;
static uint8_t cfg_flag_sync[CFG_ID_MAX];

cfg_wavelynx_t cfg_wavelynx[CFG_ID_MAX];
static uint32_t cfg_buf[sizeof(cfg_wavelynx_t)/sizeof(uint32_t)+1];

static uint32_t cfg_cacl_check_sum(const cfg_wavelynx_t* cfg){
	const uint8_t* p = (const uint8_t*)&cfg->update_version;
	const uint8_t* pend = ((const uint8_t*)cfg) + sizeof(*cfg);
	uint32_t check_sum = 0;
	
	while(p < pend){
		check_sum += *p;
		p++;
	}

	return ~ check_sum;
}

int cfg_verify(const cfg_wavelynx_t* cfg){
	const uint32_t check_sum = cfg_cacl_check_sum(cfg);
	if(check_sum != cfg->check_sum){
		return 0;
	}
	return 1;
}

static void cfg_read(uint32_t addr, cfg_wavelynx_t* cfg){
	*cfg = CFG_WAVELYNX(addr);
#if 0
	if(!cfg_verify(cfg)){
		memset(cfg, 0, sizeof(*cfg));
	}	
#endif 
}

void cfg_init(void){
	LOG2_DBG("cfg init!");
	cfg_read(CFG_MANU_ADDR, &cfg_wavelynx[CFG_ID_MANU]);
	cfg_read(CFG_USER_ADDR, &cfg_wavelynx[CFG_ID_USER]);
	cfg_flag_init = 1;
}

void cfg_clear(uint8_t id){
	if(id < CFG_ID_MAX){
		flash_erase(cfg_page_addr[id], 1);
	}
}

cfg_wavelynx_t* cfg_get(uint8_t id){
	if(id >= CFG_ID_MAX){
		return NULL;
	}
	
	if(!cfg_flag_init){
		cfg_init();
	}
	
	cfg_wavelynx_t* cfg = &cfg_wavelynx[id];
	return cfg;
}

cfg_wavelynx_t* cfg_verify_get(uint8_t id){
	cfg_wavelynx_t* cfg = cfg_get(id);
	if(cfg->magic != CFG_MAGIC){
		return NULL;
	}
	if(cfg && cfg_verify(cfg)){
		return cfg;
	}
	
	return NULL;
}

int cfg_update(void* cfg, const void* val, uint16_t len){
	if(!cfg_flag_init){
		cfg_init();
	}
	
	if(memcmp(cfg, val, len)){
		memcpy(cfg, val, len);
		return 1;
	}
	
	return 0;
}

static int cfg_do_sync(uint32_t addr, cfg_wavelynx_t* cfg){
	const uint8_t* p = (const uint8_t*)addr;
	if(memcmp(p, cfg, sizeof(*cfg))){
		
		if(cfg->magic != CFG_MAGIC){
			cfg->magic = CFG_MAGIC;
			//初始化更新版本
			cfg->update_version = 0;
		}
		else{
			//更新版本加1
			cfg->update_version++;
		}
		
		cfg->check_sum = cfg_cacl_check_sum(cfg);
		//保证4字节对齐
		cfg_buf[sizeof(cfg_buf)/sizeof(uint32_t) - 1] = ~ 0U;
		memcpy(cfg_buf, cfg, sizeof(*cfg));
		flash_erase(addr, 1);
		return flash_write(addr, (uint32_t*)cfg, sizeof(*cfg));
	}
	return 0;
}

int cfg_sync(void){
	if(!cfg_flag_init){
		LOG2_WRN("NO INIT!");
		return 0;
	}
	int ret = 0;
	for(int i = 0; i < CFG_ID_MAX; i++){
		ret |= cfg_do_sync(cfg_page_addr[i], &cfg_wavelynx[i]);
	}
	return ret;
}


